#include <iostream>
using namespace std;
#include <list>
#include <vector>
#include <map>
#include<string.h>

// 1:初始化列表
class A
{
public:
    friend ostream &operator<<(ostream &os, const A &ret);
    A() : _x(11), _y(12)
    {
    }
    A(int x, int y) : _x(x), _y(y)
    {
    }

private:
    int _x;
    int _y;
};
// 重载<<运算符
ostream &operator<<(ostream &os, const A &ret)
{
    os << ret._x << ":" << ret._y;
    return os;
}
int m1()
{
    int x = 1;
    vector<int> v1 = {1, 2, 3, 4, 5};
    vector<int> v2 = {1, 3, 4, 5, 6};

    list<int> l1 = {1, 2, 3, 4, 5};
    list<int> l2 = {12, 3, 4, 5, 6, 7};

    map<string, int> m = {{"苹果", 1}, {"西瓜", 2}, {"香蕉", 3}};
    // 类也可以使用初始化列表。
    // 相当于去调用了构造函数
    A a1(1, 2);
    A a2 = {2, 4};
    cout << a2 << endl;

    return 0;
}

// 2:类型推导:RTTI
// 表示程序运行起来对对象的类型识别
int m3()
{
    int a = 10;
    int b = 20;
    decltype(a + b) c;
    cout << typeid(c).name() << endl;
    // 这里相当于是一个函数，它会返回一个对象，然后这个对象再去调用name

    cout << "-----------" << endl;
    auto d = a + b;
    cout << typeid(d).name() << endl;

    return 0;
}

// 3:默认成员函数的控制
class date
{
public:
    date() = default; // 指定显示去生成默认构造函数
    // 没有写构造函数，而是直接去写拷贝构造
    // date(const int &a) : _a(a)
    // {
    // }
    date(const date &d) = delete;
    date &operator=(const date &dd) = delete;
    // 要求date的对象不能进行拷贝构造和赋值

private:
    int _a = 10;
};

int m4()
{
    date d1;
    // date d2(d1);

    return 0;
}




void fun(int& ret){
    cout<<"void fun(int& ret)"<<endl;
}
void fun(int&& ret){
    cout<<"void fun(int&& ret)"<<endl;
}

class String{
public:
    String(const char* str = ""){
        _str = new char[strlen(str+1)];
        strcpy(_str,str);
    }
    //s2（s1）
    String(const String& s){
        cout<<"String(const String& s)--深拷贝"<<endl;
        _str = new char[strlen(s._str)+1];
        strcpy(_str,s._str);
    }

    //s3（右值-将亡值）移动拷贝
    String(String&& s):_str(nullptr){
         cout<<"String(String&& s):_str(nullptr)--移动拷贝"<<endl;
        swap(_str,s._str);
    }

    ~String(){
        delete[] _str;
    }
private:
    char* _str;
};

String f(const char* str){
    String tmp(str);//拷贝构造
    return tmp;//返回一个临时对象，也就是将亡值
}
// 右值引用和移动语义
int main()
{
    // 左值引用：
    int a = 0;
    int &b = a;

    // 右值引用：常量，表达式，函数返回值等临时常量
    int x = 1;
    int y = 2;
    int&& ret = 10;
    int&& ret2 = x+y;

    //注意：左值引用是不能直接引用右值的
    //int& ret3 = x+y;
    const int& ret3 = x+y;

    //右值引用也不能引用左值，但是可以加上move
    int && ret4 = move(a);


    //右值做函数参数的情况
    int cc = 10;
    // fun(cc);//左值
    // fun(10);//右值

    //c++11又将右值区分为：纯右值和将亡值
    //纯右值：基本类型的常量或者临时对象
    //将亡值：自定义类型的临时对象
    String s1("左值");
    String s2(s1);//参数是左值
    //String s3(String("临时对象-右值"));//这里会被编译器优化，因为刚进行完构造函数，又马上进行拷贝构造
    String s3(f("将亡值")); //--自定义类型中的将亡值




    return 0;
}